
#include "imageRGB.h"


M3D_BEGIN_NAMESPACE

    ImageRGB::ImageRGB() {
    }

    ImageRGB::~ImageRGB() {
    }


	void ImageRGB::rgbtorgb(unsigned char *r,unsigned char *g,unsigned char *b,unsigned char *l,int n) {
    	while(n--) {
        	l[0] = r[0];
        	l[1] = g[0];
        	l[2] = b[0];
        	l += 3; r++; g++; b++;
    	}
	}

	void  ImageRGB::ConvertShort(unsigned short *array, unsigned int length) {
    	unsigned short b1, b2;
    	unsigned char *ptr;

    	ptr = (unsigned char *)array;
    	while (length--) {
        	b1 = *ptr++;
        	b2 = *ptr++;
        	*array++ = (b1 << 8) | (b2);
    	}
	}

	void ImageRGB::ConvertUint(unsigned *array, unsigned int length) {
    	unsigned int b1, b2, b3, b4;
    	unsigned char *ptr;

    	ptr = (unsigned char *)array;
    	while (length--) {
        	b1 = *ptr++;
        	b2 = *ptr++;
        	b3 = *ptr++;
        	b4 = *ptr++;
        	*array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
    	}
	}



	ImageRec* ImageRGB::ImageOpen(const char *fileName)
	{
    	union {
        	int testWord;
        	char testByte[4];
    	} endianTest;

    	ImageRec *image;
    	int swapFlag;
    	int x;

    	endianTest.testWord = 1;
    	if (endianTest.testByte[0] == 1) {
        	swapFlag = 1;
    	} else {
        	swapFlag = 0;
    	}

    	image = (ImageRec *)malloc(sizeof(ImageRec));
    	if (image == NULL) {
        	fprintf(stderr, "Out of memory!\n");
        	exit(1);
    	}
    	if ((image->file = fopen(fileName, "rb")) == NULL) {
			return NULL;
    	}

    	fread(image, 1, 12, image->file);

    	if (swapFlag) {
        	ConvertShort(&image->imagic, 6);
    	}

    	image->tmp = (unsigned char *)malloc(image->xsize*256);
    	if (image->tmp == NULL) {
        	fprintf(stderr, "\nOut of memory!\n");
        	exit(1);
    	}

    	if ((image->type & 0xFF00) == 0x0100) {
        	x = image->ysize * image->zsize * (int) sizeof(unsigned);
        	image->rowStart = (unsigned *)malloc(x);
        	image->rowSize = (int *)malloc(x);
        	if (image->rowStart == NULL || image->rowSize == NULL) {
            	fprintf(stderr, "\nOut of memory!\n");
            	exit(1);
        	}
        	image->rleEnd = 512 + (2 * x);
        	fseek(image->file, 512, SEEK_SET);
        	fread(image->rowStart, 1, x, image->file);
        	fread(image->rowSize, 1, x, image->file);
        	if (swapFlag) {
            	ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
            	ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
       		}	
    	}
    	return image;
	}

	void ImageRGB::ImageClose(ImageRec *image) {
    	fclose(image->file);
    	free(image->tmp);
    	free(image);
	}

	void ImageRGB::ImageGetRow(ImageRec *image, unsigned char *buf, int y, int z) {
    	unsigned char *iPtr, *oPtr, pixel;
    	int count;

    	if ((image->type & 0xFF00) == 0x0100) {
        	fseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
        	fread(image->tmp, 1, (unsigned int)image->rowSize[y+z*image->ysize],
              	image->file);

        	iPtr = image->tmp;
        	oPtr = buf;
        	for (;;) {
            	pixel = *iPtr++;
            	count = (int)(pixel & 0x7F);
            	if (!count) {
                	return;
            	}
            	if (pixel & 0x80) {
                	while (count--) {
                    	*oPtr++ = *iPtr++;
                	}
            	} else {
                	pixel = *iPtr++;
                	while (count--) {
                    	*oPtr++ = pixel;
                	}
            	}
        	}	
    	} else {
        	fseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
              	SEEK_SET);
        	fread(buf, 1, image->xsize, image->file);
    	}
	}

	GLubyte * ImageRGB::read_alpha_texture(const char *name, int *width, int *height)
	{
    	unsigned char *base, *lptr;
    	ImageRec *image;
    	int y;

    	image = ImageOpen(name);
    	if(!image) {
        	return NULL;
    	}

    	(*width)=image->xsize;
    	(*height)=image->ysize;
    	if (image->zsize != 1) {
      		ImageClose(image);
      	return NULL;
    	}

    	base = (unsigned char *)malloc(image->xsize*image->ysize*sizeof(unsigned char));
    	lptr = base;
    	for(y=0; y<image->ysize; y++) {
        	ImageGetRow(image,lptr,y,0);
        	lptr += image->xsize;
    	}
    	ImageClose(image);

    	return (unsigned char *) base;
	}

	GLubyte * ImageRGB::read_rgb_texture(const char *name, int *width, int *height)
	{
    	unsigned char *base, *ptr;
    	unsigned char *rbuf, *gbuf, *bbuf, *abuf;
    	ImageRec *image;
    	int y;

    	image = ImageOpen(name);
    
    	if(!image)
        	return NULL;
    	(*width)=image->xsize;
    	(*height)=image->ysize;
    	if (image->zsize != 3 && image->zsize != 4) {
      		ImageClose(image);
      		return NULL;
    	}

    	base = (unsigned char*)malloc(image->xsize*image->ysize*sizeof(unsigned int)*3);
    	rbuf = (unsigned char *)malloc(image->xsize*sizeof(unsigned char));
    	gbuf = (unsigned char *)malloc(image->xsize*sizeof(unsigned char));
    	bbuf = (unsigned char *)malloc(image->xsize*sizeof(unsigned char));
    	abuf = (unsigned char *)malloc(image->xsize*sizeof(unsigned char));
    	if(!base || !rbuf || !gbuf || !bbuf || !abuf) {
      		if (base) free(base);
      		if (rbuf) free(rbuf);
      		if (gbuf) free(gbuf);
      		if (bbuf) free(bbuf);
      		if (abuf) free(abuf);
      		return NULL;
    	}

    	ptr = base;
    	for(y=0; y<image->ysize; y++) {
        	if(image->zsize == 4) {
            	ImageGetRow(image,rbuf,y,0);
            	ImageGetRow(image,gbuf,y,1);
            	ImageGetRow(image,bbuf,y,2);
            	ImageGetRow(image,abuf,y,3);  /* Discard. */
            	rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
            	ptr += (image->xsize * 3);
        	} else {
            	ImageGetRow(image,rbuf,y,0);
            	ImageGetRow(image,gbuf,y,1);
            	ImageGetRow(image,bbuf,y,2);
            	rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
            	ptr += (image->xsize * 3);
        	}
    	}

    	ImageClose(image);
    	free(rbuf);
    	free(gbuf);
    	free(bbuf);
    	free(abuf);

    	return (GLubyte *) base;
	}



    Texture *ImageRGB::loadRGBTexture(const char *filename) {
		
		int width = 0;
		int height = 0;
        GLubyte *buffer;
        Texture *texture = (Texture *) malloc(sizeof(Texture));

        buffer = read_rgb_texture (filename, &width, &height);
        if (!buffer) {
            return NULL;
        }

        texture->width = width;
        texture->height = height;

        glGenTextures(1, &(texture->textureId));
        glBindTexture(GL_TEXTURE_2D, texture->textureId);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);

        FREEANDNULL(buffer);

        return texture;
    }


    Texture *ImageRGB::loadAlphaTexture(const char *filename) {
		
		int width = 0;
		int height = 0;
        GLubyte *buffer;
        Texture *texture = (Texture *) malloc(sizeof(Texture));

        buffer = read_alpha_texture (filename, &width, &height);
        if (!buffer) {
            return NULL;
        }

        texture->width = width;
        texture->height = height;

        glGenTextures(1, &(texture->textureId));
        glBindTexture(GL_TEXTURE_2D, texture->textureId);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		//GL_LUMINANCE: create 4 copies of  a value and set it to R G B A
		glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, height, width, 0, 
					GL_LUMINANCE, GL_UNSIGNED_BYTE, buffer);


        FREEANDNULL(buffer);

        return texture;
    }


M3D_END_NAMESPACE

